﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SwimmingCompetition.AST;
using SwimmingCompetition.Exceptions;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace SwimmingCompetition.Visitors
{
    class TreeBuilderVisitor : IEventVisitor
    {
        private EventObject _event;
        private TreeNode _treeNodeBuilder;

        public TreeBuilderVisitor()
        {
            _event = new EventObject();
            _treeNodeBuilder = new TreeNode("Event");
        }
         
        public void Visit(ABirthdayNode node)
        {
            ((LaneNode)node.Parent).Ath.Birthday = node.Text;
        }

        public void Visit(ACode node)
        {
            string urlRegex = @"[a-zA-Z]{3}[-][0-9]{6}";
            Regex validator = new Regex(urlRegex);
            string code = Utilities.RemoveQuotes(node.Text);
            if (validator.IsMatch(code))
            {
                ((LaneNode)node.Parent).Ath.Code = code;
            }
            else
            {
                throw new ACodeException("EventiATappe.Exceptions.ACodeException", "Athele code " + node.Text + " not corrected!");
            }
        }

        public void Visit(ANameNode node)
        {
            ((LaneNode)node.Parent).Ath.Name = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(ASocietyNode node)
        {
            ((LaneNode)node.Parent).Ath.Society = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(ASurnameNode node)
        {
            ((LaneNode)node.Parent).Ath.Surname = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(ATimeRegNode node)
        {
            int mm = int.Parse(node.Text.Split(':')[0]);
            int ss = int.Parse(node.Text.Split(':')[1]);

            if (mm < 0 || mm > 59 || ss < 0 || ss > 59)
            {
                throw new ATimeException("EventiATappe.Exceptions.ATimeException", "Registration Time " + node.Text + " not corrected!");
            }
            ((LaneNode)node.Parent).Ath.TimeRegistry = node.Text;
        }

        public void Visit(ATimeResultNode node)
        {
            int mm = int.Parse(node.Text.Split(':')[0]);
            int ss = int.Parse(node.Text.Split(':')[1]);

            if (mm < 0 || mm > 59 || ss < 0 || ss > 59)
            {
                throw new ATimeException("EventiATappe.Exceptions.ATimeException", "Result Time " + node.Text + " not corrected!");
            }
            ((LaneNode)node.Parent).Ath.TimeResult = node.Text;
        }

        public void Visit(CategoryCompNode node)
        {
            ((SpecCompNode)node.Parent).Competition.Category = node.Text;
        }

        public void Visit(CategoryNode node)
        {
            _event.CategoryEvent = node.Text;
        }

        public void Visit(CoadjuctorNode node)
        {
            _event.Coadjuctor = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(CompEmployeeNode node)
        {
            _event.CompEmpl = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(CompNameNode node)
        {
            node.SSComp = new StartListSingleComp();
            node.SSComp.NameSingleComp = Utilities.RemoveQuotes(node.Text);
            foreach (ASTNode childNode in node.Children)
            {
                childNode.Accept(this);
            }
            _event.StartList.Add(node.SSComp);
        }

        public void Visit(CronoServiceNode node)
        {
            _event.CronoServ = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(CronoSocietyNode node)
        {
            _event.CronoSociety = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(CronoTypeNode node)
        {
            _event.CronoType = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(DateProgCompNode node)
        {
            node.dP = new DayProgram();
            node.dP.Date = node.Text;
            foreach (ASTNode childNode in node.Children)
            {
                childNode.Accept(this);
            }
            _event.ProgramList.Add(node.dP);
        }

        public void Visit(DepJudgeNode node)
        {
            _event.Depjudge = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(DoctorNode node)
        {
            _event.Doctor = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(EndDateRegNode node)
        {
            _event.EndReg = node.Text;
        }

        public void Visit(EndNode node)
        {
            _event.EndEv = node.Text;
        }

        public void Visit(FalseStartEmployeeNode node)
        {
            _event.FSEmpl = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(HourNode node)
        {
            int hh = int.Parse(node.Text.Split(':')[0]);
            int mm = int.Parse(node.Text.Split(':')[1]);

            if (hh > 24 || hh < 0 || mm < 0 || mm > 59)//Controllo semantico sull'orario
            {
                throw new TimeOutOfBoundsException("EventiATappe.Exceptions.TimeOutOfBoundsException", "Orario " + node.Text + " non corretto!");
            }

            ((SpecCompNode)node.Parent).Competition.Hour = node.Text;
        }

        public void Visit(LaneNode node)
        {
            node.Ath = new Athlete();
            node.Ath.Lane = node.Text;
            if (int.Parse(node.Ath.Lane) <= int.Parse(_event.Lanes))
            {
                foreach (ASTNode childNode in node.Children)
                {
                    childNode.Accept(this);
                }
                ((TurnCompNode)node.Parent).ST.Athlete.Add(node.Ath);
            }
            else
            {
                throw new LaneOutOfBoundException("EventiATappe.Exceptions.LaneOutOfBoundException", "Lane " + node.Text + " not corrected!");
            }
        }

        public void Visit(LanesNode node)
        {
            _event.Lanes = node.Text;
        }

        public void Visit(LimitTimeRegNode node)
        {
            _event.LimitTime = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(LocationNode node)
        {
            _event.Location = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(ManagerNode node)
        {
            _event.Manager = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(NameCompetitionNode node)
        {
            _event.NameEvent = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(NoteNode node)
        {
            _event.Note = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(NumberTypeComp node)
        {
            ((TurnCompNode)node.Parent).ST.NumeberTurn = node.Text;
        }

        public void Visit(OrganizationNode node)
        {
            _event.Organization = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(PoolBaseNode node)
        {
            _event.PoolBase = node.Text; 
        }

        public void Visit(RefereeNode node)
        {
            _event.Referee = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(SpeakerNode node)
        {
            _event.Speaker = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(SpecCompNode node)
        {
            node.Competition = new SingleCompetition();
            node.Competition.Spec = Utilities.RemoveQuotes(node.Text);
            foreach (ASTNode childNode in node.Children)
            {
                childNode.Accept(this);
            }
            ((DateProgCompNode)node.Parent).dP.CompetitionsOfDay.Add(node.Competition);
        }

        public void Visit(StartNode node)
        {
            _event.StartEv = node.Text;
        }

        public void Visit(TurnCompNode node)
        {
            if (node.Parent is SpecCompNode)
                ((SpecCompNode)node.Parent).Competition.Turn = node.Text;
            else
            {
                node.ST = new SingleTurn();
                node.ST.NameTurn = node.Text;
                foreach (ASTNode childNode in node.Children)
                {
                    childNode.Accept(this);
                }
                ((CompNameNode)node.Parent).SSComp.StartL.Add(node.ST);
            }
        }

        public void Visit(TypeNode node)
        {
            _event.Type = Utilities.RemoveQuotes(node.Text);
        }

        public void Visit(InfoEventNode node)
        {
            foreach (ASTNode childNode in node.Children)
            {
                childNode.Accept(this);
            }
        }


        public void Visit(EventNode node)
        {
            foreach (ASTNode childNode in node.Children)
            {
                childNode.Accept(this);
            }

            TreeNode _eventNode =new TreeNode("NameEvent(" + _event.NameEvent + ")");
            TreeNode _infoevent = new TreeNode("InfoEvent");
            _infoevent.Nodes.Add("Category(" + _event.CategoryEvent + ")");
            _infoevent.Nodes.Add("Location(" + _event.Location + ")");
            _infoevent.Nodes.Add("Type(" + _event.Type+ ")");
            _infoevent.Nodes.Add("Start Date(" + _event.StartEv+ ")");
            _infoevent.Nodes.Add("End date(" + _event.EndEv+ ")");
            _infoevent.Nodes.Add("End Date Registry(" + _event.EndReg+ ")");
            _infoevent.Nodes.Add("Poolbase(" +_event.PoolBase + ")");
            _infoevent.Nodes.Add("Limit Time(" + _event.LimitTime + ")");
            _infoevent.Nodes.Add("Lanes(" + _event.Lanes + ")");
            _eventNode.Nodes.Add(_infoevent);

            TreeNode _jury =  new TreeNode("Jury");
            _jury.Nodes.Add("Referee(" + _event.Referee + ")");
            _jury.Nodes.Add("Coadjuctor(" + _event.Coadjuctor + ")");
            _jury.Nodes.Add("Depjudge(" + _event.Depjudge + ")");
            _jury.Nodes.Add("False start Employee(" + _event.FSEmpl + ")");
            _jury.Nodes.Add("Competition Employee(" + _event.CompEmpl + ")");
            _eventNode.Nodes.Add(_jury);

            TreeNode _crono = new TreeNode("Crono");
            _crono.Nodes.Add("Type(" + _event.CronoType  + ")"); 
            _crono.Nodes.Add("Service(" + _event.CronoServ + ")");
            _crono.Nodes.Add("Society(" + _event.CronoSociety + ")");
            _eventNode.Nodes.Add(_crono);

            TreeNode _other = new TreeNode("Other");
            _other.Nodes.Add("Speaker(" + _event.Speaker + ")");
            _other.Nodes.Add("Doctor(" + _event.Doctor+ ")");
            _other.Nodes.Add("Manager(" + _event.Manager + ")");
            _eventNode.Nodes.Add(_other);

            TreeNode _program =  new TreeNode("Program");
            for (int i = 0; i < _event.ProgramList.Count; i++)
            {
                TreeNode _dayProgram =  new TreeNode(_event.ProgramList[i].Date);
                for(int j=0; j< _event.ProgramList[i].CompetitionsOfDay.Count; j++)
                {
                    TreeNode _competition =  new TreeNode("Speciality("+ _event.ProgramList[i].CompetitionsOfDay[j].Spec+")");
                    _competition.Nodes.Add("Hour("+_event.ProgramList[i].CompetitionsOfDay[j].Hour+")");
                    _competition.Nodes.Add("Category("+ _event.ProgramList[i].CompetitionsOfDay[j].Category+")");
                    _competition.Nodes.Add("Turn("+ _event.ProgramList[i].CompetitionsOfDay[j].Turn+")");
                    _dayProgram.Nodes.Add(_competition);
                }
                _program.Nodes.Add(_dayProgram);
            }
            _eventNode.Nodes.Add(_program);

            TreeNode _startList = new TreeNode("Startlist");
            for (int i = 0; i < _event.StartList.Count; i++)
            {
                TreeNode _competition = new TreeNode("Competition("+_event.StartList[i].NameSingleComp+")");
                for (int j = 0; j < _event.StartList[i].StartL.Count; j++)
                {
                    TreeNode _turn = new TreeNode("Turn("+_event.StartList[i].StartL[j].NameTurn + " " + _event.StartList[i].StartL[j].NumeberTurn+")");
                    for(int k=0; k<_event.StartList[i].StartL[j].Athlete.Count; k++)
                    {
                        TreeNode _athlete= new TreeNode("Lane("+_event.StartList[i].StartL[j].Athlete[k].Lane+")");
                        _athlete.Nodes.Add("Code("+_event.StartList[i].StartL[j].Athlete[k].Code +")");
                        _athlete.Nodes.Add("Surname(" + _event.StartList[i].StartL[j].Athlete[k].Surname +")");
                        _athlete.Nodes.Add("Name("+ _event.StartList[i].StartL[j].Athlete[k].Name +")");
                        _athlete.Nodes.Add("Society("+ _event.StartList[i].StartL[j].Athlete[k].Society +")");
                        _athlete.Nodes.Add("Birthday("+ _event.StartList[i].StartL[j].Athlete[k].Birthday +")");
                        _athlete.Nodes.Add("TimeRegistry(" + _event.StartList[i].StartL[j].Athlete[k].TimeRegistry + ")");
                        _turn.Nodes.Add(_athlete);
                    }
                    _competition.Nodes.Add(_turn);
                }
                _startList.Nodes.Add(_competition);
            }
            _eventNode.Nodes.Add(_startList);
            
            _treeNodeBuilder.Nodes.Add(_eventNode);

            TreeViewASTForm view = new TreeViewASTForm();
            view.TreePaint(_eventNode);
            view.Show();
        }


        public void Visit(StartListNode node)
        {
            foreach (ASTNode childNode in node.Children)
            {
                childNode.Accept(this);
            }
        }


        public void Visit(JuryNode node)
        {
            foreach (ASTNode childNode in node.Children)
            {
                childNode.Accept(this);
            }

            
        }

        public void Visit(OtherNode node)
        {
            foreach (ASTNode childNode in node.Children)
            {
                childNode.Accept(this);
            }
        }

        public void Visit(ProgNode node)
        {
            foreach (ASTNode childNode in node.Children)
            {
                childNode.Accept(this);
            }
        }


        public void Visit(TimingNode node)
        {
            foreach (ASTNode childNode in node.Children)
            {
                childNode.Accept(this);
            }
        }
    }
}
